#include "FDEB.h"
#include "FDEBCompatibility.h"

#include <fstream>
#include <vector>
#include <string>
#include <stdexcept>
#include <iomanip>

void buildCompatibilityLists(std::vector<FDEBEdge>& edges, double threshold) {
    size_t n = edges.size();
    for (size_t i = 0; i < n; ++i) {
        for (size_t j = i + 1; j < n; ++j) {
            double compatibility = calculateCompatibility(edges[i], edges[j]);
            if (compatibility > threshold) {
                edges[i].compatibilityList.push_back(&edges[j]);
                edges[j].compatibilityList.push_back(&edges[i]);
            }
        }
    }
}


void applyEdgeForces(std::vector<FDEBEdge>& edges, double stepSize) {
    for (FDEBEdge& edge : edges) {
        std::vector<FPoint>& points = edge.subdivisionPoints;
        std::vector<Vector2D> forces(points.size(), {0.0, 0.0});

        for (FDEBEdge* compatibleEdge : edge.compatibilityList) {
            const std::vector<FPoint>& compatPoints = compatibleEdge->subdivisionPoints;

            size_t n = std::min(points.size(), compatPoints.size());
            for (size_t i = 1; i < n - 1; ++i) {
                double fx = compatPoints[i].lon - points[i].lon;
                double fy = compatPoints[i].lat - points[i].lat;
                forces[i].x += fx;
                forces[i].y += fy;
            }
        }

        for (size_t i = 1; i < points.size() - 1; ++i) {
            points[i].lon += forces[i].x * stepSize;
            points[i].lat += forces[i].y * stepSize;
        }
    }
}


void runFDEB(std::vector<FDEBEdge>& edges, const FDEBOptions& options) {
    double currentStepSize = options.S;

    for (int phase = 0; phase < options.K; ++phase) {
        for (int iter = 0; iter < options.C; ++iter) {
            applyEdgeForces(edges, currentStepSize);
        }

        if (phase < options.K - 1) {
            for (FDEBEdge& edge : edges) {
                edge.refineSubdivisionPoints();
            }

            currentStepSize *= 0.5; // 冷却
        }
    }
}


void writeBundledEdgesToCSV(const std::vector<FDEBEdge>& edges, const std::string& filename) {
    std::ofstream ofs(filename);
    if (!ofs) {
        throw std::runtime_error("Cannot open file " + filename);
    }

    // CSV表头
    ofs << "edge_id,point_index,lon,lat\n";

    // 写数据，保留小数点后8位
    ofs << std::fixed << std::setprecision(8);

    for (size_t e = 0; e < edges.size(); ++e) {
        const auto& edge = edges[e];
        for (size_t i = 0; i < edge.subdivisionPoints.size(); ++i) {
            const auto& pt = edge.subdivisionPoints[i];
            ofs << e << ',' << i << ',' << pt.lon << ',' << pt.lat << '\n';
        }
    }

    ofs.close();
}